#include <STM32FreeRTOS.h>
#include "hwboard.h"
#include "plc_abi.h"
#include <pt100_hx711.h>
#include "ad7689.h"

#ifdef USE_DISPLAY

#include <oled.h>
#include <ssd1322_io_hz.h>

#endif

#include <MCPDAC.h>
#include <ShiftRegister74HC595.h>
#include <IWatchdog.h>
#include <plc_rte.h>
#include <kSerial.h>

#ifdef USE_KVDB

#include <retain_kvdb.h>
#include <IPAddress.h>

#endif

#include "retain_lfs.h"
#include <nSPI.h>

#include "SPIFlash.h"

#ifndef THIS_IS_BOOTLOADER
pt100_hx711 hx1(PE11, PE12);
pt100_hx711 hx2(PE13, PE14);
pt100_hx711 hx3(PE15, PB10);
pt100_hx711 hx4(PD12, PD13);

SWSPI spi(PD11, PD9, PD8, PD10);
AD7689 ad(&spi, 8);

MCPDACClass mcp;

ShiftRegister74HC595 sr(3, PD5, PD3, PD2);
nSPI spi1(PB_5, PB_4, PB_3);
void *spi_lock = nullptr;

#endif
#ifdef USE_CH423

#include "ch423.h"
#include "I2C_Driver.h"
#include "pb_decode.h"
#include "Holder.h"
#include "inline_ctrl.h"

I2C_Driver i2c(PB_9, PB_8);
// TwoWire i2c(PB9, PB8);
ch423 ich423(&i2c);
#endif
#ifdef USE_DISPLAY
ssd1322_io_hz ssd1322(PB8, PB9, PE0, PC3, PA0, PB0);
oled dis_abi;
#endif
#ifdef USE_PCF8563

#endif

#undef read
#undef write
#undef close

#define X1 PD4
#define X2 PD7
#define X3 PB6
#define X4 PB7
#ifdef B1260
#define X5 PD6
#else
#define X5 PE0
#endif
#define X6 PE1
#define X7 PE2
#define X8 PE3
#define X9 PE4
#define X10 PE5
#define X11 PE6
#define X12 PC13
#define X13 PC14
#define X14 PC15
#define X15 PC0
#define X16 PC2
const u8 _xport[] = {X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16};
const u8 *boardBase::xport = _xport;
const u8 xport_5[] = {PD4, PD7, PB6, PB7, PE0, PE1, PC8, PE3, PE4, PE5, PE6, PC13, PC14, PC15, PC0, PE10};
const u8 boardBase::yport[] = {};
#ifdef PLC
extern "C" int __init();
#endif
extern "C" void MX_USART1_UART_Init(void);

hwboard::hwboard() {
#ifdef THIS_IS_BOOTLOADER
    MX_USART1_UART_Init();
#else
    SCB->VTOR = (uint32_t) &VECTOR_ISR;
#endif
    rte_data.xa_ori = xa_ori;
    rte_data.xa_ori_count = IO_XA_NRS;
}

extern "C" {
void eth_reset() {
    // ETH RESET
    pinMode(PA5, OUTPUT);
    pinMode(PB2, OUTPUT);
    digitalWrite(PA5, LOW);
    digitalWrite(PB2, LOW);
    delay(300);
    digitalWrite(PA5, HIGH);
    digitalWrite(PB2, HIGH);
    delay(100);
}
}

void SMI_Init();

uint8_t ksz8863_reg(uint8_t addr);

uint8_t ksz8863;
u8 XA7 = PA4;

void xport_isr0() {
    rte_data.XCOUNT[0]++;
    rte_data.X[0] = !digitalRead(xport_5[0]);
}

void xport_isr1() {
    rte_data.XCOUNT[1]++;
    rte_data.X[1] = !digitalRead(xport_5[1]);
}

void xport_isr2() {
    rte_data.XCOUNT[2]++;
    rte_data.X[2], !digitalRead(xport_5[2]);
}

void xport_isr3() {
    rte_data.XCOUNT[3]++;
    rte_data.X[3] = !digitalRead(xport_5[3]);
}

void xport_isr4() {
    rte_data.XCOUNT[4]++;
    rte_data.X[4] = !digitalRead(xport_5[4]);
}

void xport_isr5() {
    rte_data.XCOUNT[5]++;
    rte_data.X[5] = !digitalRead(xport_5[5]);
}

void xport_isr6() {
    rte_data.XCOUNT[6]++;
    rte_data.X[6] = !digitalRead(xport_5[6]);
}

void xport_isr7() {
    rte_data.XCOUNT[7]++;
    rte_data.X[7] = !digitalRead(xport_5[7]);
}

std::function<void()> xport_isr[8] = {
        xport_isr0, xport_isr1, xport_isr2, xport_isr3, xport_isr4, xport_isr5,
        xport_isr6, xport_isr7};

int hwboard::begin(uint32_t tick) {
    rte_data.XCLEAR = XCLEAR;
    rte_data.XCLEAR_count = IO_XI_NRS;
    rte_data.xa32 = xa32;
    rte_data.xa32_count = 4;
    rte_data.XCOUNT = XCOUNT;
    rte_data.XCOUNT_count = IO_XI_NRS;
    rte_config.fil_param = fil_param;
    rte_config.fil_param_count = 14;

    // kSerial::get_mon_serial()->begin(115200);
#ifdef USE_FIRMATA_SERIAL
    kSerial::get_firmata_serial()->begin(115200);
#endif
#ifdef USE_CH423
    HAL_Delay(100);
    // i2c.begin(MASTER_ADDRESS);
    ich423.begin();
    ioled();
#endif
    spi_lock = Rtos::Create_Mutex();
#ifdef USE_DATA_FLASH
    dataFlash = new SPIFlash(&spi1, PA_15);
    dataFlash->init();
#endif

#ifndef THIS_IS_BOOTLOADER
    pinMode(PC9, INPUT);
    rte.data.rst_mode = IWatchdog.isReset();
    eth_reset();
    SMI_Init();
    // KSZ8863_Print_Reg_Value();
    // load_config();
    ksz8863 = ksz8863_reg(166);
    core_debug("ksz8863 0x%x 0x%x", ksz8863_reg(0), ksz8863);

    if (ksz8863 == 0x43) {
        core_debug("MLL");
        model = 4;
    } else if (ksz8863 == 0x53) {
        core_debug("RLL");
        pinMode(PE7, INPUT_PULLDOWN);
        pinMode(PE8, INPUT_PULLDOWN);
        pinMode(PE9, INPUT_PULLDOWN);
        HAL_Delay(10);
        if ((digitalRead(PE7) == 1) || (digitalRead(PE8) == 1) || (digitalRead(PE9) == 1))
            model = 4;
        else {
            model = 3;
        }
    } else {
        core_debug("Hardware Error!");
        rte.event(pb_event_HARDWARE_ERROR, true);
        ioled();
        while (true) {
            //
        }
    }
    core_debug("Hardware Model=%d", model);
    if (model == 4) {
        LED_RUN = PE_9;
        LED_ERR = PE_8;
        LED_ETH = PE_7;
        XA4 = PA5;
        digitalWrite(PA5, LOW);
    }
#ifndef USE_DISPLAY
    pinMode(LED_RUN, OUTPUT);
    pinMode(LED_ERR, OUTPUT);
    pinMode(LED_ETH, OUTPUT);
    digitalWriteFast(LED_ERR, LOW);
    digitalWriteFast(LED_RUN, LOW);
    digitalWriteFast(LED_ETH, LOW);
#endif
    delay(10);

#ifdef USE_DISPLAY
    delay(10);
    ssd1322.begin();
    ssd1322.drawCentreString("kVPAC Controller", 128, 0, 1);
    ssd1322.setCursor(0, 40);
    ssd1322.print("Ver:");
    ssd1322.print(PLC_RTE_VER_MAJOR);
    ssd1322.print('.');
    ssd1322.print(PLC_RTE_VER_MINOR);
    ssd1322.print('.');
    ssd1322.print(BUILD_NUMBER);
    dis_abi.begin(&ssd1322);
#endif

    pinMode(PC12, OUTPUT);
    digitalWrite(PC12, LOW);

    sr.begin();
    sr.setAllLow();

    mcp.begin(PC7, PC6, PD15, PD14);
    mcp.setGain(false, true);
    mcp.setGain(true, true);
    mcp.ShutDown(false, false);
    mcp.ShutDown(true, false);
    if (model == 3) {
        for (int i = 0; i < IO_XI_NRS; i++)
            pinMode(xport[i], INPUT_PULLUP);
        //        for (int i = 0; i < 8; i++) {
        //            attachInterrupt(xport[i], xport_isr[i], CHANGE);
        //        }
    } else {
        for (int i = 0; i < IO_XI_NRS; i++)
            pinMode(xport_5[i], INPUT_PULLUP);
        //        for (int i = 0; i < 8; i++) {
        //            attachInterrupt(xport_5[i], xport_isr[i], CHANGE);
        //        }
    }
    pinMode(XA4, INPUT_ANALOG);
    pinMode(XA7, INPUT_ANALOG);
    for (auto &i: _ina) {
        i.begin(0, 65535);
    }

    analogReadResolution(12);
    ad.begin();
    rte.data.wdg_en = 0;

    // atemp_init = analogRead(ATEMP);
    hx1.begin();
    hx2.begin();
    hx3.begin();
    hx4.begin();

    enOut = 1;
    enInput = 1;
    return boardBase::begin(tick);
#else
    return 0;
#endif
}

#ifndef THIS_IS_BOOTLOADER

int hwboard::get_dbg_jmpr_get() {
    IWatchdog.reload();
    return 0;
}

int hwboard::get_rst_jmpr_get() {
    return 0;
}

#endif
#undef poll
const u8 asc[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
#define RED 2
#define GREEN 1
#define BLUE 3

void hwboard::ioled() {
    bool changed = false;
    if (rte.data.state != plc_state)
        changed = true;
    plc_state = rte.data.state;
#ifdef USE_CH423
    switch (rte.data.state) {
        case (u8) pb_state_USB_INSERTED:
            ich423.setChar('U', GREEN);
            break;
        case (u8) pb_state_USB_COPYING:
            ich423.setChar('C', GREEN);
            break;
            //        case (u8) pb_state_USB_COPIED:
            //            ich423.setChar('D', GREEN);
            //            break;
        case (u8) pb_state_USB_NO_FILE:
            ich423.setChar('n', GREEN);
            break;
        case (u8) pb_state_BOOT_CHECK_RTE_BAD:
            ich423.setChar('R', RED);
            break;
        case (u8) pb_state_BOOT_WAIT_USB:
            ich423.setChar('d', GREEN);
            break;
        case (u8) pb_state_WAIT_USB_OFF:
            ich423.setChar('u', BLUE);
            break;
        case (u8) pb_state_power_on:
        case (u8) pb_state_Booting:
            ich423.setChar(asc[BUILD_NUMBER % sizeof(asc)], GREEN);
            break;
#ifndef THIS_IS_BOOTLOADER
        case (u8) pb_state_FLASH_FORMAT:
            ich423.setChar('F', BLUE);
            break;
        case (u8) pb_state_PLC_ERROR:
            ich423.setChar('E', RED);
            break;
        case (u8) pb_state_STATE_POWER_FAULT:
            ich423.setChar('e', RED);
            break;
        case (u8) pb_state_Empty:
            ich423.setChar('N', BLUE);
            break;

        case (u8) pb_state_APP_FLASH_END:
            ich423.setChar('E', GREEN);
            break;
        case (u8) pb_state_APP_FLASHING:
            ich423.setChar('W', GREEN);
            break;
        case (u8) pb_state_Stopped:
            ich423.setChar('T', GREEN);
            break;
        case (u8) pb_state_Started:
            if (rte_data.prompt > 0x20 && millis() & 0x800) {
                ich423.setChar(rte_data.prompt, BLUE);
            } else {
                for (int i = 0; i < IO_XI_NRS; i++) {
                    if (rte_data.X[i] != digitalValue[i]) {
                        changed = true;
                        digitalValue[i] = rte_data.X[i];
                    }
                }
                for (int i = 0; i < IO_YO_NRS; i++) {
                    if (rte_data.Y[i] != digitalValue[IO_XI_NRS + i]) {
                        changed = true;
                        digitalValue[IO_XI_NRS + i] = rte_data.Y[i];
                    }
                }
                if (rte_data.alarm != alarm) {
                    changed = true;
                    alarm = rte_data.alarm;
                }
                if (rte.data.state != status) {
                    changed = true;
                    status = rte.data.state;
                }
                if (changed) {
                    for (int i = 0; i < 16; i++) {
                        char v = rte_data.X[i];
                        ich423.setBit(i / 8, i % 8, v);
                    }
                    for (int i = 0; i < 8; i++) {
                        char v = rte_data.alarm & (1 << i);
                        ich423.setBit(2, i, v ? 2 : 0);
                    }
                    for (int i = 0; i < 24; i++) {
                        char v = rte_data.Y[i];
                        ich423.setBit(i / 8 + 3, i % 8, v);
                    }
                    for (int i = 0; i < 8; i++) {
                        char v = rte_data.alarm & (1 << (7 - i));
                        ich423.setBit(6, i, v ? 2 : 0);
                    }
                    for (int i = 0; i < 8; i++) {
                        char v = rte.data.state & (1 << (7 - i));
                        ich423.setBit(7, i, v ? 3 : 0);
                    }
                }
            }
            break;
#endif
        default:
            break;
    }
    if (changed)
        ich423.update();
#endif
}

uint32_t last_led_tick;

extern "C" {
void net_led_on() {
#ifndef USE_DISPLAY
    digitalWrite(board.LED_ETH, LOW);
#endif
}

void net_led_off() {
#ifndef USE_DISPLAY
    digitalWrite(board.LED_ETH, HIGH);
#endif
}
}

#undef close

int Serial_diag(serial_t *serial) {
    //    logger.debug("CR1 = 0x%x\n",
    //                 (uint32_t) serial->uart->CR1); /*!< USART Control register 1,                 Address offset: 0x00 */
    //    logger.debug("CR2 = 0x%x\n",
    //                 (uint32_t) serial->uart->CR2); /*!< USART Control register 2,                 Address offset: 0x04 */
    //    logger.debug("CR3 = 0x%x\n",
    //                 (uint32_t) serial->uart->CR3); /*!< USART Control register 3,                 Address offset: 0x08 */
    //    logger.debug("BRR = 0x%x\n",
    //                 (uint32_t) serial->uart->BRR); /*!< USART Baud rate register,                 Address offset: 0x0C */
    //    logger.debug("GTPR = 0x%x\n",
    //                 (uint32_t) serial->uart->GTPR); /*!< USART Guard time and prescaler register,  Address offset: 0x10 */
    //    // logger.debug("PA MODER=0x%x,OTYPE=0x%x", GPIOA->MODER, GPIOA->OTYPER);
    //    int iser = NVIC->ISER[1] & (1 << (37 - 32));
    //    int cr1 = USART1->CR1 & (1 << 5);
    //    if (cr1 == 0 || iser == 0) {
    //        logger.error("rx irq disable. iser=%d cr1=%d", iser, cr1);
    //    }
    return 0;
}

uint32_t next_tick;

#ifndef THIS_IS_BOOTLOADER

int hwboard::test_hw() {
    return 0;
}

void hwboard::board_output(uint32_t tick) {
    for (int i = 0; i < 8; i++) {
        if (rte_data.XCLEAR[i]) {
            rte_data.XCOUNT[i] = 0;
        }
    }
    for (int i = 0; i < IO_XA_NRS; i++) {
        _ina[i].set_factory(rte_config.fil_param[i]);
    }
    hx1.set_factory(rte_config.fil_param[10]);
    hx2.set_factory(rte_config.fil_param[11]);
    hx3.set_factory(rte_config.fil_param[12]);
    hx4.set_factory(rte_config.fil_param[13]);
    for (int i = 0; i < IO_YO_NRS; i++) {
        sr.setNoUpdate(i, rte_data.Y[i]);
    }
    sr.updateRegisters();
    mcp.setVoltage(true, rte_data.YA[0]);
    mcp.setVoltage(false, rte_data.YA[1]);
    mcp.update();
    if (rte.data.wdg_en && !IWatchdog.isEnabled()) {
        IWatchdog.begin(rte_config.wdg_time * 1000);
    }
}

int hwboard::Poll(uint32_t tick) {
    IWatchdog.reload();
    //    if (tick < next_tick)return;
    //    next_tick = tick + 100;
    if (!enInput)
        return -1;
    for (int i = 0; i < IO_XI_NRS; i++) {
        u8 val;
        if (model == 3) {
            val = !digitalRead(xport[i]);
        } else {
            val = !digitalRead(xport_5[i]);
        }
        rte_data.X[i] = val;
    }
    hx1.loop();
    hx2.loop();
    hx3.loop();
    hx4.loop();
    float v = hx1.value();

    rte_data.xa32[0] = v;
    rte_data.YA[4 + 0] = v * 10; // 保持定位符兼容,XA->YA

    v = hx2.value();

    rte_data.xa32[1] = v;
    rte_data.YA[4 + 1] = v * 10; // 保持定位符兼容,XA->YA

    v = hx3.value();

    rte_data.xa32[2] = v;
    rte_data.YA[4 + 2] = v * 10; // 保持定位符兼容,XA->YA

    v = hx4.value();

    rte_data.xa32[3] = v;
    rte_data.YA[4 + 3] = v * 10; // 保持定位符兼容,XA->YA

    rte_data.XA[18] = (hx1.da / 256);
    rte_data.XA[19] = (hx1.db / 256);
    rte_data.XA[20] = (hx2.da / 256);
    rte_data.XA[21] = (hx2.db / 256);
    rte_data.XA[22] = (hx3.da / 256);
    rte_data.XA[23] = (hx3.db / 256);
    rte_data.XA[24] = (hx4.da / 256);
    rte_data.XA[25] = (hx4.db / 256);
    ad.acquire(0);
    rte_data.xa_ori[0] = ad.samples[0];
    rte_data.xa_ori[1] = ad.samples[1];
    rte_data.xa_ori[2] = ad.samples[2];
    rte_data.xa_ori[3] = ad.samples[3];
    rte_data.xa_ori[4] = analogRead(XA4);
    rte_data.xa_ori[5] = ad.samples[4];
    rte_data.xa_ori[6] = ad.samples[5];
    rte_data.xa_ori[7] = analogRead(XA7);
    rte_data.xa_ori[8] = ad.samples[6];
    rte_data.xa_ori[9] = ad.samples[7];

    // 通道9,10零值(4mA)锁定,
    //@4mA ,adc=65535*4/20=13107
    // 满量程500A(0~20mA),@10A,adc=65535*10/500=1310
    if ((rte_data.xa_ori[8] > (13107 - 1310)) && (rte_data.xa_ori[8] < (13107 + 1310)))
        rte_data.xa_ori[8] = 13107;
    if ((rte_data.xa_ori[9] > (13107 - 1310)) && (rte_data.xa_ori[9] < (13107 + 1310)))
        rte_data.xa_ori[9] = 13107;

    for (int i = 0; i < 10; i++) {
        // AD失效判断
        if ((i < 4) && (0 < rte_data.xa_ori[i]) && (65535 > rte_data.xa_ori[i])) {
            rte_data.pwr_fault = 0;
            if (rte.data.state == pb_state_STATE_POWER_FAULT) {
                rte.set_state(pb_state_Started);
            }
        }
        _ina[i].poll(tick, (u16) rte_data.xa_ori[i]);
        // analogValue[i ] = _ina[i].value();
        rte_data.XA[i] = _ina[i].value();
    }
    if ((rte_data.pwr_fault++ > 25) && (rte.data.state == pb_state_Started)) {
        rte.set_state(pb_state_STATE_POWER_FAULT);
    }
    ioled();
    return 0;
}


void hwboard::plc_run_stop() {
    digitalWriteFast(LED_RUN, LOW);
}

void hwboard::plc_run_start() {
    if (digitalReadFast(LED_RUN) && (Rtos::ticks() - last_led_tick) > 200) {
        digitalWriteFast(LED_RUN, LOW);
        last_led_tick = Rtos::ticks();
    }
}

void hwboard::plc_run_end() {
    if (!digitalReadFast(LED_RUN) && (Rtos::ticks() - last_led_tick) > 200) {
        digitalWriteFast(LED_RUN, HIGH);
        last_led_tick = Rtos::ticks();
    }
}

#ifdef __PLATFORMIO_BUILD_DEBUG__
int hwboard::dev_test(uint32_t tick)
{
    return boardBase::dev_test(tick);
}
#endif
#endif

void hwboard::plc_run_error() {
#ifndef B1260
    digitalWriteFast(LED_ERR, LOW);
#endif
}

void hwboard::plc_run_empty() {
    digitalWriteFast(LED_RUN, LOW);
}

void hwboard::boot_mode_enter() {
    vTaskDelay(1000);
    // May reset the system now
    HAL_NVIC_SystemReset();
}

void write_outwords_cb(uint16_t, uint16_t, uint16_t *) {
    //
}

void write_bits_cb(uint16_t, uint16_t, uint8_t *) {
    //
}

void hwboard::led_run(int on) {
    if (on)
        digitalWriteFast(LED_RUN, LOW);
    else
        digitalWriteFast(LED_RUN, HIGH);
}

void hwboard::led_err(int on) {
    if (on)
        digitalWriteFast(LED_ERR, LOW);
    else
        digitalWriteFast(LED_ERR, HIGH);
}

#ifndef THIS_IS_BOOTLOADER
kSerial k1(PA_10, PA_9, false, false, false, 115200);
kSerial k4(PC_11, PC_10);
kSerial *kSerial::Serials[] = {&k1, &k4};
const u8 kSerial::Serials_nrs = 2;

kSerial *kSerial::get_serial(int fd) {
    return kSerial::Serials[fd];
}

kSerial *kSerial::get_mon_serial() {
    return kSerial::Serials[0];
}

kSerial *kSerial::get_firmata_serial() {
    return kSerial::Serials[0];
}

#endif
PinName hwboard::LED_RUN = PB_0;
PinName hwboard::LED_ERR = PA_0;

#ifdef USE_KVDB
struct fdb_default_kv_node default_kv_table[3] = {
    {"version", (void *)"2.0", 0, KV_STR_VALUE}, /* string KV */
    {"model", (void *)HWMODEL, 0, KV_STR_VALUE}, /* string KV */
};

size_t default_kv_table_nrs = 2;
#endif

void hwboard::led(uint32_t tick) {
    if (rte.data.state < (u8) pb_state_Stopped) {
        led_run(tick & 0x80);
    }
    if (rte.data.state > (u8) pb_state_Started) {
        led_run(tick & 0x40);
    }
}

int hwboard::run(uint32_t tick) {
    ioled();
    return boardBase::run(tick);
}

void Holder::set_default() {
    rte_config.build = BUILD_NUMBER;
    rte_config.wdg_time = 2000;
    for (int i = 0; i < 14; i++) {
        rte_config.fil_param[i] = 100;
    }
    rte_config.fil_param[8] = 1000;
    rte_config.fil_param[9] = 1000;
    rte_config.lwip.ip = (DEFAULT_IP4 << 24) | (DEFAULT_IP3 << 16) | (DEFAULT_IP2 << 8) | DEFAULT_IP1;
    rte_config.lwip.mask = 0xffffff;
    rte_config.lwip.gw = (DEFAULT_IP3 << 16) | (DEFAULT_IP2 << 8) | DEFAULT_IP1 | 1 << 24;
#if LWIP_DNS
    rte_config.lwip.dns = (1 << 24) | (DEFAULT_IP3 << 16) | (DEFAULT_IP2 << 8) | DEFAULT_IP1;
#endif
    rte_config.has_lwip = 1;
#ifdef __PLATFORMIO_BUILD_DEBUG__
    rte_config.log_level = KLOG_LEVEL_DEBUG;
#else
    rte_config.log_level = KLOG_LEVEL_INFO;
#endif
    rte_config.retain_disable = false;
    rte_config.reportInterval = 1000;
    rte_config.forward_timeout = 3000;
    rte_config.main_loop_interval = 100;
    for (int i = 0; i < IO_XI_NRS; ++i) {
        rte_config.XI_PORT[i] = i;
    }
    for (int i = 0; i < IO_YO_NRS; ++i) {
        rte_config.YO_PORT[i] = i;
    }
    for (int i = 0; i < IO_XA_NRS; ++i) {
        rte_config.XA_PORT[i] = i;
    }
    for (int i = 0; i < IO_YA_NRS; ++i) {
        rte_config.YA_PORT[i] = i;
    }
    rte_config.low_memory = 4096;
}
